package controller.parameterpanels;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JTextField;

import model.auxillary.Parameter;
import model.auxillary.ParameterCollectionScaling;
import model.auxillary.ParameterListScaling.ParameterType;
import model.scaling.IEBenchmarkScaling;
import model.scaling.IFactory;
import view.AlphaTextField;
import view.EBenchmarkPanel;
import view.IObserver;
import view.NumericalTextField;
import view.parameterpanels.FactoryParameterPanel;
import controller.CtrInformationPanel;
import controller.IControllable;

//#Neu
/**
* The class {@code CtrFactoryPanel} controls the behavior of a factory
* input parameter panel. 
* @author Sebastian Perlwitz
*
*/
public class CtrFactoryPanel implements IControllable, IObserver {

	/**
	 * The controller of the information panel.
	 */
    private CtrInformationPanel infoPanelController;
    
    /**
     * This controller's view.
     */
    private FactoryParameterPanel paramPanel;

    /**
     * The type of parameter the controller's view shows. I.e. geometry
     * parameters, process parameters etc.
     */
    private ParameterType parameterType;
    
    /**
     * The referenced calculation model.
     */
    private IEBenchmarkScaling eBenchmarkScaling;
    
    /**
     * The referenced model.
     */
    private IFactory factory;
    
    /**
     * To create a new {@code CtrFactoryPanel}.
     * @param eBenchmarkScaling the eBenchmarkScaling model connected to 
     * the controller.
     * @param infoPanelCtr the information panel controller.
     */
	public CtrFactoryPanel(
			IEBenchmarkScaling eBenchmarkScaling,
            CtrInformationPanel infoPanelController) {
		this.eBenchmarkScaling = eBenchmarkScaling;
        this.infoPanelController = infoPanelController;
        parameterType = ParameterType.FACTORY_PARAMETER;
        
        // Set factory as the first factory that was created.
        factory = eBenchmarkScaling.getFactory(1);
        
        createView(null);
        init();
	}
	
	@Override
	public void createView(String logoPath) {
		
		paramPanel = new FactoryParameterPanel(infoPanelController, factory);
		FactoryParameterPanel factoryPanel =
				(FactoryParameterPanel) paramPanel;
		
		// To add listeners to the buttons "+" and "-".
		factoryPanel.getAddFactoryButton().addActionListener(
				addFactoryListener());
		factoryPanel.getRemoveFactoryButton().addActionListener(
				removeFactoryListener());
	}
	
	/**
	 * To create a listener for the button that adds a new factory.
	 * @return The button's listener.
	 */
	private ActionListener addFactoryListener() {
		return new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					addParameterPanel(
							eBenchmarkScaling.addFactory().
							getParameterCollection(parameterType));
					paramPanel.revalidate();
				}
			};
	}
		
	/**
	 * To create a listener for the button that removes a new factory.
	 * @return The button's listener.
	 */
	private ActionListener removeFactoryListener() {
		return new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				// There must be at least one factory.
				if(eBenchmarkScaling.getFactories().size() > 1) {
					removeParameterPanel();
					eBenchmarkScaling.removeFactory();
					paramPanel.revalidate();	
				}								
			}			
		};
	}
	
	/**
     * To change the text of a parameter panel's border. 
     * @param textField the AlphaTextField.
     * @param newText the text to be set for the border.
     */
	public void changeBorderText(AlphaTextField textField, String newText) {
		
		// Change the corresponding border text when the user renamed the 
		// factory.
		FactoryParameterPanel facilityPanel =
				(FactoryParameterPanel) paramPanel;
		int panelIndex = 
				facilityPanel.getFactoryNameTextFields().indexOf(textField);
		paramPanel.setBorderText(panelIndex, newText);
	}
	
	/**
     * To add a document listener to every text field of a parameter panel.
     * The view of this controller gets registered as an observer in the model.
     * @param textFields the text fields.
     */
	private void addTextFieldListeners(List<JTextField> textFields) {
		
		// When new text fields are added get the new factory.
		factory = eBenchmarkScaling.getFactory(
				eBenchmarkScaling.getFactories().size());
		
		// Register this controller and the paramPanel as an observer in 
		// factory.
		factory.registerObserver(this);
		factory.registerObserver(paramPanel);
		
		// To add text field listeners to the numerical text fields and
		// the text fields that rename a factory.
		List<JTextField> numTextFields =
				new ArrayList<JTextField>();
		List<AlphaTextField> alphaTextFields = 
				new ArrayList<AlphaTextField>();
		
		for(JTextField textField : textFields) {
			if(textField instanceof NumericalTextField) {
				numTextFields.add((NumericalTextField) textField);
			} else if(textField instanceof AlphaTextField) {
				alphaTextFields.add((AlphaTextField) textField);
			}
		}
		
		// Add the listeners to the numerical text fields.
		Parameter param;
	    String paramID;
    	for(JTextField textField : numTextFields) {    		
    		NumericalTextField numTF = (NumericalTextField) textField;
    		paramID = numTF.getParameterID();
    		param = factory.getParameter(paramID);
    		numTF.addDocumentListener(
    				new ListenerNumericalTF(numTF, param, this));
    	}
		
    	// Add the listeners to the alpha text fields/the text fields that 
    	// rename a factory.
		for(AlphaTextField textField : alphaTextFields) {
			textField.addDocumentListener(new ListenerAlphaTextField(
					textField,
					this,
					factory,
					eBenchmarkScaling));
		}
	}
	
	/**
	 * To initiate the view of this controller.
	 */
	private void init() {
		List<ParameterCollectionScaling> collections = 
				factory.getParameters(parameterType);
    	for (ParameterCollectionScaling collection : collections) {
    		addParameterPanel(collection);  				
    	}
    }

	/**
     * To add a parameter panel to the view.
     * @param collection the parameter collection whose parameter panels get
     * drawn.
     */
	private void addParameterPanel(ParameterCollectionScaling collection) {
		
		//Add the factory Panel.
		FactoryParameterPanel facilityPanel = 
				(FactoryParameterPanel) paramPanel;
		addTextFieldListeners(
				facilityPanel.addParameterSet(
						createParamInfo(collection),					
						collection.getName(),
						collection.getScalingID()));
	}
	
	/**
     * To remove the last parameter panel from the view.
     */
    public void removeParameterPanel() {
    	paramPanel.removeParameterPanel();
    }
	
	/**
     * To create the necessary information to create a new parameter panel.
     * @param collection the parameters whose parameter panels get created.
     * @return the parameter information.
     */
    private List<String[]> createParamInfo(
    		ParameterCollectionScaling collection) {
    	List<String[]> paramsInfo = new ArrayList<String[]>();
		for (Parameter param : collection.getParameters()) {
			String[] paramInfo = new String[5];
			paramInfo[0] = param.getName();
			paramInfo[1] = param.getKey();
			paramInfo[2] = param.getGuiAbbreviation();
			paramInfo[3] = param.getUnit();
			
			if (Double.isNaN(param.getValue()) || 
					param.getValue() == null) {
				paramInfo[4] = "";
			} else {
				paramInfo[4] = String.valueOf(param.getValue());
			}
			paramsInfo.add(paramInfo);
		}
		return paramsInfo;
    }
    
    /**
     * To tell the controller that another invalid input was written into
     * one of the text fields.
     */
    public void addInvalidInput() {
    	infoPanelController.getView().showInvalidInputError();
    	paramPanel.setErrorStatus(true);
    	factory.notifyObservers();
    	eBenchmarkScaling.notifyObservers();
    }
    
    /**
     * To tell the controller that another invalid input was corrected.
     */
    public void removeInvalidInput() {
    	infoPanelController.getView().showFactoryStandardMessage();
        paramPanel.setErrorStatus(false);
        factory.notifyObservers();
        eBenchmarkScaling.notifyObservers();
    }

    @Override
    public EBenchmarkPanel getView() {
        return paramPanel;
    }

	@Override
	public void update() {
		// Nothing to do here.
	}

}
